#region Copyright (c) 2000-2013 Developer Express Inc.
/*
{*******************************************************************}
{                                                                   }
{       Developer Express .NET Component Library                    }
{                                                                   }
{                                                                   }
{       Copyright (c) 2000-2013 Developer Express Inc.              }
{       ALL RIGHTS RESERVED                                         }
{                                                                   }
{   The entire contents of this file is protected by U.S. and       }
{   International Copyright Laws. Unauthorized reproduction,        }
{   reverse-engineering, and distribution of all or any portion of  }
{   the code contained in this file is strictly prohibited and may  }
{   result in severe civil and criminal penalties and will be       }
{   prosecuted to the maximum extent possible under the law.        }
{                                                                   }
{   RESTRICTIONS                                                    }
{                                                                   }
{   THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES           }
{   ARE CONFIDENTIAL AND PROPRIETARY TRADE                          }
{   SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS   }
{   LICENSED TO DISTRIBUTE THE PRODUCT AND ALL ACCOMPANYING .NET    }
{   CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY.                 }
{                                                                   }
{   THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED      }
{   FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE        }
{   COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE       }
{   AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT  }
{   AND PERMISSION FROM DEVELOPER EXPRESS INC.                      }
{                                                                   }
{   CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON       }
{   ADDITIONAL RESTRICTIONS.                                        }
{                                                                   }
{*******************************************************************}
*/
#endregion Copyright (c) 2000-2013 Developer Express Inc.

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Collections;
using System.Windows.Documents;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
#if TESTUTILS
namespace DevExpress.Xpf.DemoBase.TestUtils {
#else 
#if SLDESIGN
namespace DevExpress.Xpf.Core.Design.CoreUtils {
#else
#if DXWINDOW
namespace DevExpress.Internal.DXWindow {
#else
namespace DevExpress.Xpf.Core.Native {
#endif
#endif
#endif
#if !SILVERLIGHT || SLDESIGN
	public static class LayoutHelper {
		public static bool IsChildElement(DependencyObject root, DependencyObject element) {
			DependencyObject parent = element;
			while(parent != null) {
				if(parent == root)
					return true;
				parent = LayoutHelper.GetParentCore(parent);
			}
			return false;
		}
		public static IEnumerable GetRootPath(DependencyObject root, DependencyObject element) {
			DependencyObject parent = element;
			while(parent != null) {
				yield return parent;
				if(parent == root)
					break;
				parent = LayoutHelper.GetParent(parent);
			}
		}
		public static bool IsChildElementEx(DependencyObject root, DependencyObject element) {
			return IsChildElementEx(root, element, false);
		}
		public static bool IsChildElementEx(DependencyObject root, DependencyObject element, bool useLogicalTree) {
			DependencyObject parent = element;
			while(parent != null) {
				if(parent == root)
					return true;
				if(parent is ContextMenu)
					parent = ((ContextMenu)parent).PlacementTarget;
				else if(parent is Popup)
					parent = ((Popup)parent).PlacementTarget;
				else
					parent = LayoutHelper.GetParentCore(parent, useLogicalTree);
			}
			return false;
		}
		public static DependencyObject FindRoot(DependencyObject d) {
			DependencyObject current = d;
			while(GetParent(current) != null)
				current = GetParent(current);
			return current;
		}
		public static FrameworkElement GetTopLevelVisual(DependencyObject node) {
			FrameworkElement topElement = (FrameworkElement)node;
			while(node != null) {
				node = VisualTreeHelper.GetParent(node);
				if(node is FrameworkElement)
					topElement = node as FrameworkElement;
			}
			return topElement;
		}
		public static Rect GetRelativeElementRect(UIElement element, UIElement parent) {
			GeneralTransform transform = element.TransformToVisual(parent);
			return transform.TransformBounds(new Rect(element.RenderSize));
		}
		public static UIElement GetTopContainerWithAdornerLayer(UIElement element) {
			FrameworkElement fElement = element as FrameworkElement;
			if(fElement != null && LayoutHelper.GetParent(element) == null){
				return LayoutHelper.FindElement(fElement, (e) => (AdornerLayer.GetAdornerLayer(e) != null));
			}
			DependencyObject currentObject = element;
			UIElement topContainer = null;
			while(currentObject != null) {
				UIElement currentUIElement = currentObject as UIElement;
				if(currentUIElement != null && AdornerLayer.GetAdornerLayer(currentUIElement) != null)
					topContainer = (UIElement)currentObject;
				currentObject = VisualTreeHelper.GetParent(currentObject);
			}
			return topContainer;
		}
		static bool CheckIsDesignTimeRoot(DependencyObject d) {
			FrameworkElement elem = d as FrameworkElement;
			if(elem != null) {
				elem = VisualTreeHelper.GetParent(d) as FrameworkElement;
				if(elem != null) {
					elem = elem.TemplatedParent as FrameworkElement;
					if(elem != null && (elem.GetType().Name.Contains("DesignTimeWindow") || elem.GetType().Name.Contains("WindowInstance"))) return true;
				}
			}
			return false;
		}
		public static DependencyObject GetParent(DependencyObject d) {
			return GetParent(d, false);
		}
		static DependencyObject GetParentCore(DependencyObject d) {
			return GetParentCore(d, false);
		}
		public static DependencyObject GetParent(DependencyObject d, bool uselogicalTree) {
			if(System.ComponentModel.DesignerProperties.GetIsInDesignMode(d)) {
				if(CheckIsDesignTimeRoot(d)) return null;
			}
			return GetParentCore(d, uselogicalTree);
		}
		static DependencyObject GetParentCore(DependencyObject d, bool uselogicalTree) {
			DependencyObject parent = LogicalTreeHelper.GetParent(d);
			if(!uselogicalTree || parent == null)
				if(d is Visual) parent = VisualTreeHelper.GetParent(d);
			return parent;
		}
		public static T FindParentObject<T>(DependencyObject child) where T : class {
			while(child != null) {
				if(child is T)
					return child as T;
				child = VisualTreeHelper.GetParent(child);
			}
			return null;
		}
		public static T FindLayoutOrVisusualParentObject<T>(DependencyObject child) where T : class {
			return FindLayoutOrVisualParentObject<T>(child, false);
		}
		public static DependencyObject FindLayoutOrVisualParentObject(DependencyObject child, Type parentType) {
			return FindLayoutOrVisualParentObject(child, parentType, false);
		}
		public static T FindLayoutOrVisualParentObject<T>(DependencyObject child, bool useLogicalTree) where T : class {
			return FindLayoutOrVisualParentObject(child, typeof(T), useLogicalTree) as T;
		}
		public static DependencyObject FindLayoutOrVisualParentObject(DependencyObject child, Type parentType, bool useLogicalTree) {
			return FindLayoutOrVisualParentObject(child, element => parentType.IsAssignableFrom(element.GetType()), useLogicalTree);
		}
		public static DependencyObject FindLayoutOrVisualParentObject(DependencyObject child, Predicate<DependencyObject> predicate, bool useLogicalTree) {
			while(child != null) {
				if(predicate(child))
					return child;
				child = GetParent(child, useLogicalTree);
			}
			return null;
		}
		public static DependencyObject FindLayoutOrVisualParentObject(DependencyObject child, Predicate<DependencyObject> predicate) {
			return FindLayoutOrVisualParentObject(child, predicate, false);
		}
		public static Size MeasureElementWithSingleChild(UIElement element, Size constraint) {
			UIElement child = (VisualTreeHelper.GetChildrenCount(element) > 0) ? (VisualTreeHelper.GetChild(element, 0) as UIElement) : null;
			if(child != null) {
				child.Measure(constraint);
				return child.DesiredSize;
			}
			return new Size();
		}
		public static Size ArrangeElementWithSingleChild(UIElement element, Size arrangeSize, Point position) {
			UIElement child = (VisualTreeHelper.GetChildrenCount(element) > 0) ? (VisualTreeHelper.GetChild(element, 0) as UIElement) : null;
			if(child != null)
				child.Arrange(new Rect(position, arrangeSize));
			return arrangeSize;
		}
		public static Size ArrangeElementWithSingleChild(UIElement element, Size arrangeSize) {
			return ArrangeElementWithSingleChild(element, arrangeSize, new Point(0, 0));
		}
		public static FrameworkElement GetRoot(FrameworkElement element) {
			FrameworkElement current = element;
			while(GetParent(current) != null)
				current = (FrameworkElement)GetParent(current);
			return current;
		}
		public static FrameworkElement FindElement(FrameworkElement treeRoot, Predicate<FrameworkElement> predicate) {
			VisualTreeEnumerator en = new VisualTreeEnumerator(treeRoot);
			while(en.MoveNext()) {
				FrameworkElement element = en.Current as FrameworkElement;
				if(element != null && predicate(element))
					return element;
			}
			return null;
		}
		public static FrameworkElement FindElementByName(FrameworkElement treeRoot, string name) {
			return FindElement(treeRoot, element => element.Name == name);
		}
		public static FrameworkElement FindElementByType(FrameworkElement treeRoot, Type type) {
			return FindElement(treeRoot, element => element.GetType() == type);
		}
		public delegate void ElementHandler(FrameworkElement e);
		public static void ForEachElement(FrameworkElement treeRoot, ElementHandler elementHandler) {
			VisualTreeEnumerator en = new VisualTreeEnumerator(treeRoot);
			while(en.MoveNext()) {
				FrameworkElement element = en.Current as FrameworkElement;
				if(element != null)
					elementHandler(element);
			}
		}
		public static bool IsPointInsideElementBounds(Point position, FrameworkElement element, Thickness margin) {
			Rect rect = new Rect(-margin.Left, -margin.Top, element.ActualWidth + margin.Right + margin.Left, element.ActualHeight + margin.Bottom + margin.Top);
			return rect.Contains(position);
		}
	}
#endif
	public delegate bool SkipLayout(UIElement elem);
	public delegate bool IsLastChild(UIElement elem);
	public static class DockPanelLayoutHelper {
		public static Size MeasureDockPanelLayout(FrameworkElement parent, Size constraint) {
			return MeasureDockPanelLayout(parent, constraint, null);
		}
		public static Size MeasureDockPanelLayout(FrameworkElement parent, Size constraint, SkipLayout skipLayout) {
			double maxWidth = 0.0;
			double MaxHeight = 0.0;
			double totalWidth = 0.0;
			double totalHeight = 0.0;
			int count = VisualTreeHelper.GetChildrenCount(parent);
			for(int i = 0; i < count; i++) {
				UIElement element = VisualTreeHelper.GetChild(parent, i) as UIElement;
				if(element == null || (skipLayout != null && skipLayout(element))) continue;
				Size availableSize = new Size(Math.Max(0, constraint.Width - totalWidth), Math.Max(0, constraint.Height - totalHeight));
				element.Measure(availableSize);
				Size desiredSize = element.DesiredSize;
				switch(DockPanel.GetDock(element)) {
					case Dock.Left:
					case Dock.Right:
						MaxHeight = Math.Max(MaxHeight, totalHeight + desiredSize.Height);
						totalWidth += desiredSize.Width;
						break;
					case Dock.Top:
					case Dock.Bottom:
						maxWidth = Math.Max(maxWidth, totalWidth + desiredSize.Width);
						totalHeight += desiredSize.Height;
						break;
				}
			}
			maxWidth = Math.Max(maxWidth, totalWidth);
			return new Size(maxWidth, Math.Max(MaxHeight, totalHeight));
		}
		public static Size ArrangeDockPanelLayout(FrameworkElement parent, Size arrangeSize, bool lastChildFill) {
			return ArrangeDockPanelLayout(parent, arrangeSize, lastChildFill, null, null);
		}
		public static Size ArrangeDockPanelLayout(FrameworkElement parent, Size arrangeSize, bool lastChildFill, SkipLayout skipLayout, IsLastChild isLastChild) {
			double x = 0;
			double y = 0;
			double totalWidth = 0;
			double totalHeight = 0;
			int count = VisualTreeHelper.GetChildrenCount(parent);
			int lastDockableChildIndex = count - (lastChildFill ? 1 : 0);
			for(int i = 0; i < count; i++) {
				UIElement element = VisualTreeHelper.GetChild(parent, i) as UIElement;
				if(element == null) continue;
				if(skipLayout != null && skipLayout(element)) {
					element.Arrange(new Rect(0, 0, 50, 50));
					continue;
				}
				Size desiredSize = element.DesiredSize;
				Rect finalRect = new Rect(x, y, Math.Max(0, arrangeSize.Width - (x + totalWidth)), Math.Max(0, arrangeSize.Height - (y + totalHeight)));
				bool lastChild = isLastChild != null ? isLastChild(element) : i == lastDockableChildIndex;
				if(!lastChild) {
					switch(DockPanel.GetDock(element)) {
						case Dock.Left:
							x += desiredSize.Width;
							finalRect.Width = desiredSize.Width;
							break;
						case Dock.Top:
							y += desiredSize.Height;
							finalRect.Height = desiredSize.Height;
							break;
						case Dock.Right:
							totalWidth += desiredSize.Width;
							finalRect.X = Math.Max((double)0.0, (double)(arrangeSize.Width - totalWidth));
							finalRect.Width = desiredSize.Width;
							break;
						case Dock.Bottom:
							totalHeight += desiredSize.Height;
							finalRect.Y = Math.Max((double)0.0, (double)(arrangeSize.Height - totalHeight));
							finalRect.Height = desiredSize.Height;
							break;
					}
				}
				element.Arrange(finalRect);
			}
			return arrangeSize;
		}
	}
}
